package com.cloud.common.loadbalance;

import org.springframework.cloud.client.ServiceInstance;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 服务实例状态
 *
 * @author fengwenjin
 */
public class ServiceInstanceStatus {
    private final int failureThreshold = 1;
    private final int maxCircuitTrippedMillis = 30000;
    private final int timeWindowIntervalMillis = 180000;

    private AtomicInteger totalRequestsCount = new AtomicInteger(0);
    private AtomicInteger activeRequestsCount = new AtomicInteger(0);
    private AtomicInteger connectionFailureCount = new AtomicInteger(0);

    private volatile long lastActiveRequestTime;
    private volatile long lastConnectionFailureTime;

    private ServiceInstance serviceInstance;

    public ServiceInstanceStatus(ServiceInstance instance) {
        this.serviceInstance = instance;
    }

    public ServiceInstance getServiceInstance() {
        return serviceInstance;
    }

    public void incrementActiveRequestsCount() {
        totalRequestsCount.incrementAndGet();
        activeRequestsCount.incrementAndGet();
        lastActiveRequestTime = System.currentTimeMillis();
    }

    public void decrementActiveRequestsCount() {
        if (activeRequestsCount.decrementAndGet() < 0) {
            activeRequestsCount.set(0);
        }
        lastActiveRequestTime = System.currentTimeMillis();
    }

    public int getTotalRequestsCount() {
        int count = totalRequestsCount.get();
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastActiveRequestTime > timeWindowIntervalMillis || count < 0) {
            totalRequestsCount.set(0);
            return 0;
        }
        return count;
    }

    public int getActiveRequestsCount() {
        int count = activeRequestsCount.get();
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastActiveRequestTime > timeWindowIntervalMillis || count < 0) {
            activeRequestsCount.set(0);
            return 0;
        }
        return count;
    }

    public boolean isCircuitBreakerTripped() {
        long circuitBreakerTimeout = getCircuitBreakerTimeout();
        if (circuitBreakerTimeout <= 0) {
            return false;
        }
        return circuitBreakerTimeout > System.currentTimeMillis();
    }

    private long getCircuitBreakerTimeout() {
        int failureCount = connectionFailureCount.get();
        if (failureCount < failureThreshold) {
            return 0;
        }
        return lastConnectionFailureTime + maxCircuitTrippedMillis;
    }

    public void incrementConnectionFailureCount() {
        lastConnectionFailureTime = System.currentTimeMillis();
        connectionFailureCount.incrementAndGet();
    }

    public void clearConnectionFailureCount() {
        connectionFailureCount.set(0);
    }
}
